define(['js/events' + $E.jsv, 
        'js/customer' + $E.jsv, 
        'js/objective' + $E.jsv], 
        function(Events, Customer, Objective) {
	
	var Project = function(id, name, token, digest, groupId, groupName, roles) {
		this.events = Events.create('Project.mobile');

		/**
		 * 项目登录凭据
		 * @property token
		 * @type {string}
		 */
		this.id = id;
		this.pubSqlMaxRows = 3000;
		
		this.name = name;
		this.token = token;
		this.digest = digest;
		this.groupId = groupId,
		this.roles = roles;
		this.container = $('#mainBody');

		/**
		 * 项目数据库连接池
		 *
		 * @property dbPool
		 * @type {string}
		 */
		this.dbPool = '';
		/**
		 * 数据库类型表
		 */
		this.dbtypes = {};
		/**
		 * 服务器命令缓存
		 */
		this.srvcmds = {};

		/**
		 * SQL查询结果全局缓存
		 *
         * 	cache : {
		 * 		key: {string} 缓存数据的主键 cacheId,
		 * 		value: {object} 缓存数据
		 * 	}
		 *
		 * @property cache
		 * @type {object}
		 */
		this.cache = {};
		
		/**
		 * 个性化数据缓存
		 * @property storage
		 * @type {object}
		 */
		this.storage = {};

		/**
		 * 系统参数表
		 *
		 * @property params
		 * @type {object}
		 */
		this.params = {};

		/**
		 * 业务组件表
		 * 	addin: {
		 * 		id: {string} 组件ID
		 * 		name: {string} 组件名称
		 * 		type: {boolean} 组件类型
		 * 		multiple: {boolean} 是否允许多实例
		 * 	}
		 *
		 * @property addins
		 * @type {array}
		 */
		this.addins = [];
		
		/**
		 * 工单三的framemap
		 * @private
		 * @type {Array}
         */
		this.woFrameMaps = [];
		
		/**
		 * 市场活动缓存表
		 * 	objectiveType: {
		 * 		id: 市场活动ID,
		 * 		name: {string} 市场活动名称
		 * 		multiple: {boolean} 市场活动是否允许多实例
		 * 		addinId: {string} 组件ID
		 * 		addinCmtId : {string} 组件的CmtId
		 * 	}
		 *
		 * @property objectiveTypes
		 * @type {array}
		 */
		this.objectiveTypes = [];

		/**
		 * SQL查询结果全局缓存
		 *
         * 	cache : {
		 * 		key: {string} 缓存数据的主键 cacheId,
		 * 		value: {object} 缓存数据
		 * 	}
		 *
		 * @property cache
		 * @type {object}
		 */
		this.cache = {};

        /**
         * 项目上的公共属性，用于跨动态页面传递数据
         */
        this.attributes = {};

        //用来缓存当前项目的customer的所有字段
        this.customerFieldsCache = {
        		fields : [],
        		fieldsMap : {},
        		selectColumn : ''
        };
        /**
         * Project当前用户（对每个Project唯一）
         * @property customer
         * @type {customer}
         */
        this.customer = Customer.create(this);

        /**
         * Project匿名用户（对每个Project唯一）
         * @property tempCustomer
         * @type {customer}
         * @private
         */
        this.tempCustomer = Customer.create(this);

        /**
         * Project当前联系人（对每个Project唯一）
         */
        this.contactCustomer = Customer.create(this);
        
        /**
         * 用于管理在同一个菜单项目下打开的多个动态页面层
         */
        this.stacks = [];
        this.curStack = false;

		/**
		 * 实例对象缓存
		 * @property moduleInstanceMap
		 * @type {object}
		 * @private
		 */
        this.moduleInstanceMap = {};

		return this;
    };

	Project.prototype = {
			
		/**
		 * 初始化项目
		 */
		init : function(asyncJobs) {
			var proj = this;
			asyncJobs.push(function(jobCallback) {
				$E.async.parallel([function(callback) {
					proj.initParameters(function() {
						callback(null, 'parameters');
					})
				}, function(callback) {
					proj.initAddins(function() {
						callback(null, 'addins');
					})
				}, function(callback) {
					proj.initCache(function() {
						callback(null, 'caches');
					});
				}, function(callback) {
					// SAAS模式，且登录的并非主库
					if ($E.dataService.saas && $E.staff.epidDbPool) {
						proj.initSaasObjectiveTypes(function() {
							callback(null, 'objectiveTypes');
						})
					} else {
						proj.initObjectiveTypes(function() {
							callback(null, 'objectiveTypes');
						})
					}
				}, function(callback) {
					proj.initWoFrameMaps(function() {
						callback(null, 'woFrameMaps');
					})
				}, function(callback) {
					proj.initCustomerFields(function() {
						callback(null, 'customerFields');
					})
				}], function(err, result){
					if (err)
						$F.err(proj.name, err);
					else
						$F.log(proj.name, 'Initialize successed', result);
					proj.initEvents();
					jobCallback();
				})
			})
		},

		/*
		 * 初始化系统参数
		 */
		initParameters : function(callback) {
			var proj = this, mt = new Date();
			$F.log(proj.name, 'Initialize system parameters');
			$('.loading_msg').text('Initialize system parameters');
			// SQL: select PARAMETER_ID, PARAMETERVALUE, ROLEGROUP_ID from SYSC_PARAMETER{C1}
			$F.dataService('SystemDo2', {
				data : $F.sqlbean('System.parameters', proj.token, [ $E.staff.epidSql, proj.groupId ]),
                digest : proj.digest,
				success : function(data) {
					if (data.code < 1)
						alert(data.message);
					else {
						if (data.value[0].count >= 0) {
							$.each(data.value[0].fields, function(i, v) {
								v[0] = v[0].toUpperCase().trim();
								var value = ($F.isNull(v[1]) ? '' : v[1].trim());
								if (proj.params[v[0]] == undefined)
									proj.params[v[0]] = value;
								else {
									if (!!v[2])
										proj.params[v[0]] = value;
								}
							});
							$('.loading_msg').text($('.loading_msg').text() + ', done');
							// console.log(proj.params);
							
							var maxrow = parseInt(proj.params['MAXROW']);
							if (! isNaN(maxrow))
								proj.pubSqlMaxRows = maxrow;

						} else {
							$F.err('Project - initParameters', $F.lang('db.error') + data.value[0].key);
						}
					}
					callback();
				}
			});
		},

		/*
		 * 初始化系统组件
		 */
		initAddins : function(callback) {
			var proj = this, mt = new Date();
			$F.log(proj.name, 'Initialize system addins');
			$('.loading_msg').text('Initialize system addins');
			$F.dataService('SystemDo2', {
				data : $F.sqlbean('System.addins', proj.token, []),
                digest : proj.digest,
				success : function(data) {
					if (data.code < 1)
						alert(data.message);
					else {
						if (data.value[0].count >= 0) {
							proj.addins = [];
							$.each(data.value[0].fields, function(i, v) {
								proj.addins.push({
									id : v[0].toUpperCase(),
									name : v[1],
									type : v[2],
									multiple : v[3],
									notes : v[4]
								});
							});
							$('.loading_msg').text($('.loading_msg').text() + ', done');
							// console.log(proj.addins);
						} else {
							$F.err('Project - initAddins', $F.lang('db.error') + data.value[0].key);
						}
					}
					callback();
				}
			});
		},
		
		/**
		 * 初始化工单三mapid
		 */
		initWoFrameMaps : function(callback){
			var proj = this, mt = new Date();
			$F.log(proj.name, 'Initialize woFrameMap');
			$F.dataService('SystemDo2', {
				data : $F.sqlbean('System.woFrameMaps', proj.token, [$E.staff.epidSql]),
                digest : proj.digest,
				success : function(data) {
					if (data.code < 1)
						$F.alert(data.message);
					else {
						if (data.value[0].count >= 0) {
							proj.woFrameMaps = [];
							$.each(data.value[0].fields, function(i, v) {
								proj.woFrameMaps.push({
									id : v[0].trim().toUpperCase(),			// 市场活动ID（其实是mapId）
									name : v[1],	 						// 市场活动名称
									multiple : v[2],	 					// 是否允许多实例
									addinId : v[3].trim().toUpperCase(),	// 关联组件的ID
									addinCmtId : v[4].trim(),				// 关联组件的CmtId
									workorderFrameId : v[5]					// 真正的市场活动id（objectivetype表的id）
								});
							});
						} else {
							$F.err('Project - initWoFrameMaps', $F.lang('db.error') + data.value[0].key);
						}
					}
					callback();
				}
			});
		},

		/*
		 * 初始化市场活动缓存
		 */
		initSaasObjectiveTypes : function(callback) {
			var proj = this, reqData, mt = new Date();
			$F.log(proj.name, 'Initialize saas objective type');
			$('.loading_msg').text('Initialize saas objective type');
			$F.dataService('SystemDo2', {
				data : $F.sqlbean2('System.objectiveTypes', proj.token, '#DefaultMainDB', []),
                digest : proj.digest,
				success : function(data) {
					if (data.code < 1)
						$F.alert(data.message);
					else {
						if (data.value[0].count >= 0) {
							proj.objectiveTypes = [];
							$.each(data.value[0].fields, function(i, v) {
								proj.objectiveTypes.push({
									id : v[0].trim().toUpperCase(),			// 市场活动ID
									name : v[1],	 						// 市场活动名称
									multiple : v[2],	 					// 是否允许多实例
									addinId : v[3].trim().toUpperCase(),	// 关联组件的ID
									addinCmtId : v[4].trim()				// 关联组件的CmtId
								});
							});
							$('.loading_msg').text($('.loading_msg').text() + ', done');
							// console.log(proj.objectiveTypes);
							
							$F.log(proj.name, 'Initialize objective types');
							$('.loading_msg').text('Initialize objective type');
							$F.dataService('SystemDo2', {
								data : $F.sqlbean('System.objectiveTypes.SAAS', proj.token, [$E.staff.epidSql]),
				                digest : proj.digest,
								success : function(data) {
									if (data.code < 1)
										$F.alert(data.message);
									else {
										if (data.value[0].count >= 0) {
											$.each(data.value[0].fields, function(i, v) {
												proj.objectiveTypes.push({
													id : v[0].trim().toUpperCase(),			// 市场活动ID
													name : v[1],	 						// 市场活动名称
													multiple : v[2],	 					// 是否允许多实例
													addinId : v[3].trim().toUpperCase(),	// 关联组件的ID
													addinCmtId : v[4].trim()				// 关联组件的CmtId
												});
											});
											$('.loading_msg').text($('.loading_msg').text() + ', done');
											// console.log(proj.objectiveTypes);
										} else {
											$F.err('Project - initSaasObjectiveTypes', $F.lang('db.error') + data.value[0].key);
										}
									}
									callback();
								}
							});
						} else {
							$F.err('Project - initSaasObjectiveTypes', $F.lang('db.error') + data.value[0].key);
						}
					}
				}
			});
		},
	       
        initCache : function(callback){
            //select workorderstepstatus_id,workorderstepstatusdesc from sysc_workorderstepstatus            
            var ret = this.commonQuerySync("ECore.CodeTable.c_freedate", []);
            var freeDate = {};
            if(!$F.isNull(ret)){
                ret.value[0].fields.forEach(function(fd){
                    freeDate[fd] = fd;
                });
            }
            this.putCache($CONST.CacheName.FREE_DATE, freeDate);

            //SELECT CallResultReason_ID, CallResultReasonDescription, TimeAdd, CloseOB, OBStatus, ObjectiveStatus,FAILUREFLAG,MAXTIMES,objectivetype_id,togrpflag,togrp FROM SYSC_CallResultReason
            ret = this.commonQuerySync("ECore.CodeTable.sysc_callresultreason", []);
            var crrs = {};
            if(ret){
            	crrs = $F.makeJsonArrayMap(ret.value[0], 'CALLRESULTREASON_ID');
            }
            this.putCache($CONST.CacheName.CALL_RESULT_REASON, crrs);

			ret = this.commonQuerySync('ECore.Codetable.objectivesubstatus', []);
			var osss = {};
			if(ret){
				osss = $F.makeJsonArrayMap(ret.value[0], 'OBJECTIVESUBSTATUS_ID');
			}
			this.putCache($CONST.CacheName.OBJECTIVE_SUB_STATUS, osss);
			callback();
        },

		/*
		 * 初始化市场活动缓存
		 */
		initObjectiveTypes : function(callback) {
			var proj = this, mt = new Date();
			$F.log(proj.name, 'Initialize objective type');
			$('.loading_msg').text('Initialize objective type');
			// SQL: ID, DESCIPTION, DUPLICATE, ADDINID, ADDINCMTID
			$F.dataService('SystemDo2', {
				data : $F.sqlbean('System.objectiveTypes', proj.token, []),
                digest : proj.digest,
				success : function(data) {
					if (data.code < 1)
						alert(data.message);
					else {
						if (data.value[0].count >= 0) {
							proj.objectiveTypes = [];
							$.each(data.value[0].fields, function(i, v) {
								proj.objectiveTypes.push({
									id : v[0].trim().toUpperCase(),			// 市场活动ID
									name : v[1],	 						// 市场活动名称
									multiple : v[2],	 					// 是否允许多实例
									addinId : v[3].trim().toUpperCase(),	// 关联组件的ID
									addinCmtId : v[4].trim()				// 关联组件的CmtId
								});
							});
							$('.loading_msg').text($('.loading_msg').text() + ', done');
							// console.log(proj.objectiveTypes);
						} else {
							$F.err('Project - initObjectiveTypes', $F.lang('db.error') + data.value[0].key);
						}
					}
					callback();
				}
			});
		},
        
		/*
		 * 缓存用户表结构字段
		 */
        initCustomerFields : function(callback) {
            // 获取用户表结构字段
            var proj = this, mt = new Date();
			$F.log(proj.name, "Initialize customer fields");
			$('.loading_msg').text('Initialize customer fields');
            $F.dataService('SystemDo2', {
                data: $F.sqlbean('ECore.Customer.selectCustomerForField', proj.token, [$E.staff.epidSql]),
                digest : proj.digest,
                success: function(data){
                    if (data.code < 1)
                        $F.alert(data.message);
                    else {
                        if (data.value[0].count >= 0) {
                            var columns = data.value[0].columns;                            
                            proj.customerFieldsCache.fields = columns;
                            columns.forEach(function(col){
                            	proj.customerFieldsCache.fieldsMap[col.toLowerCase()] = '';
                            });
                            proj.customerFieldsCache.selectColumn = columns.join(",");
							$('.loading_msg').text($('.loading_msg').text() + ', done');
                        } else {
                            $F.err('Project - initCustomerFields', $F.lang('db.error') + data.value[0].key);
                        }
                    }
                    callback();
                }
            });
        },

        /**
		 * 初始化项目事件
		 * 
		 * @method initEvents
		 * @param callback
		 *            {callback} Async对象回调方法
		 * @return {project} 项目对象
		 */
        initEvents : function() {
        	var proj = this;
			$F.log(proj.name, "Initialize events");
        	proj.events.register($CONST.EVENT.OPEN_OBJ, $CONST.EVENT.LISTENERID, function(data){
                if (data.oId) {
                    $F.log("Project.Event.OPEN_OBJ", 'openAddinObjByOId: ' + data.oId);
                    proj.openAddinObjByOId(data.addinId, data.tabName, data.oId);
                } else if (data.otId) {
                    $F.log("Project.Event.OPEN_OBJ", 'openAddinObjByOtId: ' + data.otId);
                    proj.openAddinObjByOtId(data.addinId, data.tabName, data.otId);
                } else {
                    $F.err('Project.Event.OPEN_OBJ', "市场活动GUID或者客户数据对象GUID都为空。");
                }
        	});
        	proj.events.register($CONST.EVENT.OPEN_WO, $CONST.EVENT.LISTENERID, function(data){
                if(data.oId){//根据objective_guid打开工单
                    $F.log("Project.Event.OPEN_WO", "openAddinWOByOId with addinId: " + data.addinId + "   tabName: " + data.tabName + "   oId: " + data.oId);
                    proj.openAddinWOByOId(data.addinId, data.tabName, data.oId);
                }else if(data.subId){//根据协办id打开工单
                    $F.log("Project.Event.OPEN_WO", "openAddinWOByStepId with addinId: " + data.addinId + "   tabName: " + data.tabName + "   subId: " + data.subId);
                    proj.openAddinWOByStepId(data.addinId, data.tabName, data.subId);
                }else if(data.otId){//根据objectivetype_id打开工单（可能是创建新工单）
                    $F.log("Project.Event.OPEN_WO", "openAddinWOByOtId with addinId: " + data.addinId + "   tabName: " + data.tabName + "   otId: " + data.otId);
                    proj.openAddinWOByOtId(data.addinId, data.tabName, data.otId);
                }
        	});
        	proj.events.register($CONST.EVENT.OPEN_WO3, $CONST.EVENT.LISTENERID, function(data){
				if(data.oId){//根据objective_guid打开工单  taskId可以是空
					$F.log("Project.Event.OPEN_WO", "openAddinWOByOId with addinId: " + data.addinId + "   tabName: " + data.tabName + "   oId: " + data.oId + ' taskId: ' + data.taskId);
					proj.openAddinWO3ByOId(data.addinId, data.tabName, data.oId, data.taskId);
				} else if(data.otId){//根据objectivetype_id打开工单（可能是创建新工单）
					$F.log("Project.Event.OPEN_WO", "openAddinWOByOtId with addinId: " + data.addinId + "   tabName: " + data.tabName + "   otId: " + data.otId);
					proj.openAddinWO3ByOtId(data.addinId, data.tabName, data.otId);
				}
			});
        },

		/**
		 * 获得系统参数值
		 *
		 * @method getParam
		 * @param {string}
		 *            key 系统参数主键
		 * @return {string} 系统参数（强制转换为大写字符串）
		 */
		getParam : function(key) {
			return this.params[key.toUpperCase()];
		},

		/**
		 * 获得市场活动对象
		 *
		 * @method getObjectiveType
		 * @param otId {string} 市场活动ID
		 * @return {object} objectiveType
		 */
		getObjectiveType : function(otId) {
			otId = otId.toUpperCase();
			for (var i = 0; i < this.objectiveTypes.length; i++) {
				if (this.objectiveTypes[i].id == otId)
					return this.objectiveTypes[i];
			}
			return undefined;
		},

		/**
		 * 根据组件ID获取查询组件对象
		 * @method getAddin
		 * @param addinId {string} 组件ID
		 * @return {object} 组件对象
		 */
		getAddin : function(addinId) {
			addinId = addinId.toUpperCase();
			for (var i = 0; i < this.addins.length; i++) {
				if (this.addins[i].id == addinId)
					return this.addins[i];
			}
			return undefined;
		},
		
		getFrameMap : function(frameMapId) {
			frameMapId = frameMapId.toUpperCase();
			for (var i = 0; i < this.woFrameMaps.length; i++) {
				if (this.woFrameMaps[i].id == frameMapId)
					return this.woFrameMaps[i];
			}
			return undefined;
		},

		/**
		 * 从全局缓存获取一个数据对象
		 *
		 * @method getCache
		 * @param {string} key 缓存数据的主键
		 * @return 缓存数据对象
		 */
		getCache : function(key) {
			return ($F.isNull(key) ? undefined : this.cache[key]);
		},

		/**
		 * 向全局缓存放入一个数据对象
		 *
		 * @method putCache
		 * @param {string} key 缓存数据的主键 cacheId
		 * @param {object} data 数据对象
		 */
		putCache : function(key, data) {
			this.cache[key] = data;
			return this;
		},

        /**
         * 获取缓存中的值，更具缓存类型和缓存key
         * @param key
         * @param id
         * @returns {*}
         */
        getCacheValue : function(key, id) {
            var oneCache = this.cache[key];
            if(!$F.isNull(oneCache)){
                return oneCache[id];
            }
            return null;
        },
 
		setAttribute : function(key, value) {
			this.attributes[key] = value;
		},
		
		getAttribute : function(key) {
			return this.attributes[key];
		},
		
		openAddinPlugin : function(tabName, addin, addinParam, parameters) {
    		var proj = this;
    		// console.log(proj)
			if (! $E.plugins[addin.id]) {
				require(['js/plugins/' + addin.notes + $E.jsv], function(plugin){
					$E.plugins[addin.id] = plugin;
					proj.openPlugin(tabName, plugin, addin, addinParam, parameters);
				})
			} else
				proj.openPlugin(tabName, $E.plugins[addin.id], addin, addinParam, parameters);
		},
        openPlugin : function(tabName, plugin, addin, addinParam, parameters) {
    		var proj = this, avaliable = plugin.avaliable(proj, addin, addinParam, parameters);
    		if (avaliable.code <= 0) {
    			$F.alert(avaliable.message);
    			$F.err('Project - openPlugin', 'PLUGIN启动验证失败, TOKEN: ' + proj.token)
    			return null;
    		}
    		
			var proj = this, busyId = $F.busyShow('绘制页面...');
        	$E.setTitle(tabName);
        	$('#menuBody').hide();
        	proj.container.show();

        	// 创建新的层，用于展示动态页面
        	$('.stack', proj.container).hide();
			$E.resetLayout();
        	var stack = $('<div class="stack" />').appendTo(proj.container);
			if (proj.curStack) {
				stack.data('prevStack', proj.curStack);
				$E.addStep('[PLUGIN]' + tabName, tabName, function(){
					var prevStack = stack.data('prevStack'), 
						prevInstance = prevStack.data('instance'), 
						bsmenu = prevInstance.extendBSMenu,
						extFixed = prevInstance.extendFixed;
					
					//返回到这个页面时候，调用一次-101命令组
					if (prevInstance.type == 'DYN' || prevInstance.type == 'WO' || prevInstance.type == 'WO3')
						prevInstance.doCmdIncludeComponents('P-101');
					proj.clearStack(stack);
					proj.stacks.remove(stack);
					prevStack.show();

					$E.resetLayout();
					if (bsmenu)
						bsmenu.show();
					else
						$E.showMainMenu();
					if (extFixed)
						extFixed.show();
					
					$E.showNavBtn(! prevInstance.hideNavBtn);
					proj.curStack = prevStack;
				})
			}
			stack.data('instance', instance);
			proj.stacks.push(stack);
			proj.curStack = stack;

			var instance = plugin.newInstance(proj, stack, addin, addinParam, parameters);
			// 显示定制的底部菜单
			if (instance.extendBSMenu)
				instance.extendBSMenu.show();
			else
				$E.showMainMenu();
				
			// 显示定制的置顶面板
			if (instance.extendFixed)
				instance.extendFixed.show();
				
			$E.showNavBtn(! instance.hideNavBtn);
			$F.busyHide(busyId);
        },
       
        openAddinObjByOtId : function(addinId, tabName, otId, parameters) {
            var proj = this, addin = proj.getAddin(addinId), objectiveType = proj.getObjectiveType(otId);
            if (! addin)
                return $F.alert('组件不存在：' + addinId);
            if (! objectiveType)
                return $F.alert('市场活动不存在：' + otId);
            proj.openAddinObj(tabName, addin, objectiveType, undefined, parameters);
        },
        
        openAddinObjByOId : function(addinId, tabName, oId, parameters) {
            var proj = this, addin = proj.getAddin(addinId);
            if (! addin)
                return $F.alert('组件不存在：' + addinId);

            // 根据oId创建objective对象
            $F.dataService('SystemDo2', {
            	title: '读取业务数据',
                data : $F.sqlbean('DynBD.Select.Obj', proj.token, [$E.staff.epidSql, '', oId]),
                digest : proj.digest,
                success : function(data) {
                    if (data.code > 0) {
                        // console.log(data.value);
                        if (data.value[0].count < 1)
                            return $F.alert('用户数据不存在：' + oId);

                        var otId = data.value[0].fields[0][1];
                        var objectiveType = proj.getObjectiveType(otId);
                        if (! objectiveType)
                            return $F.alert('市场活动不存在：' + otId);
                        proj.openAddinObj(tabName, addin, objectiveType, oId, parameters);
                    }
                }
            })
        },
        
        openAddinObj : function(tabName, addin, objectiveType, oId, parameters) {
        	// 创建实例
			var instance = $D.createInstance(this, objectiveType.addinCmtId, objectiveType.id, oId, parameters, false, 'OBJ');
			if (! instance) {
				alert('实例创建失败');
				return;
			}
			this.openDyn(tabName, instance);
        },
        
        openAddinDyn : function(dynId, tabName, parameters, keepOpen, type, veSupport) {
        	// 创建实例
			var instance = $D.createInstance(this, dynId, '', '', parameters, false, type, veSupport);
			if (! instance) {
				alert('实例创建失败');
				return;
			}
			if (instance.stateful) {
				alert('有状态页面，装载失败');
				return;
			}
			
			if (! tabName)
				tabName = instance.struct.name;
			this.openDyn(tabName, instance);
        },
        
        /**
         * <p>
         * @description ...
         * </p>
         * @method openAddinRN
         * @param dynId
         * @param tabName
         * @param parameters
         * TODO
         * @author sherxia
         * @since 2017年3月23日
         */
        openAddinRN: function(dynId, tabName, parameters) {
        	// 创建实例
			var instance = $D.createInstance(this, dynId, '', '', parameters, false, 'RN', true);
			if (! instance) {
				alert('实例创建失败');
				return;
			}
			if (instance.stateful) {
				alert('有状态页面，装载失败');
				return;
			}
			
			if (! tabName)
				tabName = instance.struct.na;
			this.openRN(tabName, instance);
        },
        
        /**
         * <p>
         * @description
         * </p>
         * @method openRN
         * @param tabName
         * @param instance
         * @param objective
         * TODO
         * @author sherxia
         * @since 2017年3月23日
         */
        openRN : function(tabName, instance, objective) {
			var proj = this, busyId = $F.busyShow('绘制页面...');
        	$('#menuBody').hide();
        	proj.container.show();
        	
        	// 创建新的层，用于展示动态页面
        	$('.stack', proj.container).hide();
			$E.resetLayout();
        	var stack = $('<div id="dyn_react_container" class="stack body" />').appendTo(proj.container);
			$D.liveRN(instance, stack, objective);
			$F.busyHide(busyId);
        },

        openDyn : function(tabName, instance, objective) {
			var proj = this, busyId = $F.busyShow('绘制页面...');
        	$('#menuBody').hide();
        	proj.container.show();

        	// 创建新的层，用于展示动态页面
        	//$('.stack', proj.container).hide();
			$E.resetLayout();
        	var stack = $('<div class="stack" />').appendTo(proj.container);
			$D.live(instance, stack, objective);
			if (instance.runtime.page.name.startWith('@'))
				tabName = instance.runtime.page.name.substring(1);
        	$E.setTitle(tabName);

			if (proj.curStack) {
				stack.data('prevStack', proj.curStack.hide());
				$E.addStep('[DYN]' + tabName, tabName, function(){
					var prevStack = stack.data('prevStack'), prevInstance = prevStack.data('instance');
					//返回到这个页面时候，调用一次-101命令组
					if (prevInstance.type == 'DYN' || prevInstance.type == 'WO' || prevInstance.type == 'WO3')
						prevInstance.doCmdIncludeComponents('P-101');
					proj.clearStack(stack);
					proj.stacks.remove(stack);
					proj.curStack = prevStack;
					prevStack.show();

					$E.resetLayout();
					proj.arrangementStack(prevInstance);
				})
			}
			stack.data('instance', instance);
			proj.stacks.push(stack);
			proj.curStack = stack;
			proj.arrangementStack(instance);

			$F.busyHide(busyId);
        },
        
        arrangementStack : function(instance) {
			// 显示定制的底部菜单
			if (instance.extendBSMenu)
				instance.extendBSMenu.show();
			else
				$E.showMainMenu();
				
			// 显示定制的置顶面板
			if (instance.extendFixed)
				instance.extendFixed.show();
				
			$E.showNavBtn(! instance.hideNavBtn);
			$('#mainBody').css({
				top: $('header').outerHeight()
			});
			instance.fireEvent('_internal_stack_resize', {
				top: $('header').outerHeight(),
				bottom: $('footer').outerHeight()
			});
        },
        
        /**
         * 清除所有已经打开的STACK
         */
        clear : function() {
        	var proj = this;
        	$.each(proj.stacks, function(i, stack){
        		proj.clearStack(stack);
        	})
        	proj.stacks = [];
        	proj.curStack = false;
        },
        
        clearStack : function(stack) {
			var instance = stack.data('instance');
    		this.events.remove(instance.id);
    		if (instance.extendBSMenu)
    			instance.extendBSMenu.remove();
    		if (instance.extendFixed)
    			instance.extendFixed.remove();
    		
    		if ($.isFunction(instance.destroy))
    			instance.destroy();
    		instance = undefined;
			stack.remove();
		},
		
		addStep : function(instance) {
			var tabName = instance.runtime.page.name;
			if (tabName.startWith('@'))
				tabName = tabName.substring(1);
			$E.addStep('[DYN]' + tabName, tabName, function(){
				$D.prevStep(instance.runtime);
			})
        },

		makeIScroll : function() {
			if (! window.IScroll)
				return;
			if (! this.curStack) {
				// console.info('project', this);
				return;
			}
			
			var stack = this.curStack, shell = stack.find('.dyn_shell').css({position:'relative', 'overflow': 'hidden'});
			var myScroll = stack.data('iscroll');
			if (myScroll)
				return;
				//myScroll.refresh();
			else {
				myScroll = new IScroll(stack[0], {
					click: true,
					tap: true,
			        mouseWheel: true,		//允许滑轮滚动
			        hScroll: false
			        //scrollbars: true,		//有滚动条
			        //fadeScrollbars: true	//滚动时显示滚动条，默认影藏，并且是淡出淡入效果
				});
				stack.data('iscroll', myScroll);
//				shell.on('resize', function(){
//					myScroll.refresh();
//				})
			}
		},
		
        openAddinWOByOtId : function(addinId, tabName, otId, menuId, parameters, keepOpen){
            var proj = this, addin = proj.getAddin(addinId), objectiveType = proj.getObjectiveType(otId);
            if (!addin) {
            	return $F.alert('组件不存在：' + addinId);
            }
            if (!objectiveType) {
				return $F.alert('工单不存在：' + otId);
			}
            var workorder = $W.create(proj);
            $F.log("Project.mobile.openAddinWOByOtId", otId);
            workorder.loadByOtId(otId, objectiveType.multiple, addinId, tabName, parameters, keepOpen);
        },

        openAddinWOByOId : function(addinId, tabName, oId, parameters, keepOpen){
            var proj = this,addin = proj.getAddin(addinId);
            if (!addin)
                return $F.alert('组件不存在：' + addinId);
            var workorder = $W.create(proj);
            $F.log("Project.mobile.openAddinWOByOId", oId);
            workorder.loadByObjectiveGuid(oId, addinId, tabName, parameters, keepOpen);
        },

        openAddinWOByStepId : function(addinId, tabName, subId, parameters, keepOpen){
            var proj = this, addin = proj.getAddin(addinId);
            if (!addin) {
                return $F.alert('组件不存在：' + addinId);
            }
            var workorder = $W.create(proj);
            $F.log("Project.mobile.openAddinWOByStepId", subId);
            workorder.loadBySubStep(subId, addinId, tabName, parameters, keepOpen);
        },
        
        openAddinWO3ByOId : function(addinId, tabName, oId, taskId, parameters, keepOpen){
			var proj = this, addin = proj.getAddin(addinId);
			if (!addin) {
				return $F.alert('组件不存在：' + addinId);
			}
			var workorder = $W3.create(proj, addinId);
			$F.log("Project.mobile.openAddinWO3ByOId", oId);
			workorder.loadByObjectiveGuid(oId, taskId, addinId, tabName, parameters, keepOpen);
		},
		
		openAddinWO3ByOtId : function(addinId, tabName, otId, parameters, keepOpen){
            var proj = this, addin = proj.getAddin(addinId), objectiveType = proj.getFrameMap(otId);
            if (!addin) {
            	return $F.alert('组件不存在：' + addinId);
            }
			if (!objectiveType) {
				return $F.alert('工单不存在：' + otId);
			}
			var workorder = $W3.create(proj, addin.id);
            $F.log("Project.mobile.openAddinWO3ByOtId", "AddinId: " + addin.id + " otId: " + otId);
            workorder.loadByOtId(otId, objectiveType.multiple, addinId, tabName, parameters, keepOpen);
        },

        /**
         * 把TAB实例添加到全局的缓存中
         * @method addModuleInstance
         * @param moduleName {string} 组件名称
         * @param instance {object} TAB实例
         */
        addModuleInstance : function(moduleName, instance){
            if(! $F.isNull(instance)){
                var instanceMap = this.moduleInstanceMap[moduleName];
                if(instanceMap == null || instanceMap == undefined){
                    instanceMap = {};
                    this.moduleInstanceMap[moduleName] = instanceMap;
                }
                instanceMap[instance.id] = instance;
            }
        },

        /**
         * 从缓存中查询某个TAB实例
         * @method getModuleInstance
         * @param moduleName {string} 组件名称
         * @param instanceId {string} TAB实例ID
         */
       getModuleInstance : function(moduleName, instanceId){
            var instanceMap = this.moduleInstanceMap[moduleName];
            if($F.isNull(instanceMap)){
            	return null;
            } else {
                if(instanceId){
                    return instanceMap[instanceId];
                }else{
                    for(instanceId in instanceMap){
                        return instanceMap[instanceId];//当不传递instanceId时候，返回第一个实例
                    }
                }
            }
        },

        /**
         * 从缓存中删除某个TAB实例
         * @method removeModuleInstance
         * @param moduleName {string} 组件名称
         * @param instanceId {string} TAB实例ID
         */
        removeModuleInstance : function(moduleName, instanceId) {
            var instanceMap = this.moduleInstanceMap[moduleName];
            if(! $F.isNull(instanceMap)){
            	var newMap = {};
            	for(var id in instanceMap) {
            		if (id != instanceId) {
            			newMap[id] = instanceMap[id];
            		}
            	}
            	this.moduleInstanceMap[moduleName] = newMap;
            }
        },
  
		/**
		 * 获得当前客户的GUID
		 * @method getCustomerGuid
		 * @return {string}
		 */
        getCustomerGuid : function(){
            return this.customer.getValue("customer_guid");
        },
        
        /**
         * 设置当前客户
         * @param customer
         */
        setCurrentCustomer : function(customer){
            var proj = this;
            if(customer == null){
                proj.customer.clear();
            }else{
                for(var i = 0,j = customer.length;i<j;i++){
                    proj.customer.setPropertyByName(proj.customerFieldsCache.fields[i], customer[i]);
                    proj.customer.setOriginalPropertyByName(proj.customerFieldsCache.fields[i], customer[i]);
                }
            }
            proj.events.notify($CONST.ModuleEvent.ECM_CUSTOMERCHANGE);
        },
        
        /**
         * 设置当前客户，通过customerGuid
         * @param customerGuid
         * @param opts
         * @returns
         */
        setCurrentCustomerByGuid : function(customerGuid, opts){
            var async = false;
            if(opts && opts.async == true){
                async = true;
            }
            var deferred = $.Deferred();
            var proj = this;
            if($F.isNull(customerGuid) || $.trim(customerGuid) == ""){
                $F.log("elite", "clear customer");
                proj.setCurrentCustomer(null);
                deferred.resolve();
            }else{
                var sqlKey = "ECore.Customer.searchByGuid";
                $F.dataService('SystemDo2', {
                    data: $F.sqlbean(sqlKey,  proj.token, [$E.staff.epidSql, customerGuid]),
                    digest : proj.digest,
                    async : async,
                    success: function(data){
                        if (data.code < 1){
                            $F.alert(data.message);
                            return deferred.reject();
                        }
                        if (data.value[0].count >= 0) {
                            proj.setCurrentCustomer(data.value[0].fields[0]);
                            deferred.resolve();
                        } else {
                            $F.err($F.lang('db.error') + sqlKey);
                            deferred.reject();
                        }
                    },
                    fail: function(){
                        deferred.reject();
                    }
                });
            }
            return deferred.promise();
        },

        /**
         * 返回当前拨打的客户的guid
         * @returns {string}
         */
        getCurrentCalledCustomerGuid : function(){
            return this.getCustomerGuid();
        },

        /**
         * 返回当前联系客户的guid
         * @returns {string}
         */
        getCurrentContactCustomerGuid : function(){
            return this.contactCustomer.getValue("customer_guid") || '';
        },

        setCurrentContactCustomerGuid : function(ccg){
            this.contactCustomer.setValue("customer_guid", ccg);
        },

        /**
         * 清空当前客户
         */
        clearCustomer : function(){
            var proj = this,instance;
            var instance = proj.getModuleInstance($CONST.ModuleName.ADDIN_CUSTOMER);
            if(!$F.isNull(instance)){
                var custGuid = instance.getValue("temp.customer_guid", instance.runtime);
                if($F.isEmpty(custGuid)){
                    $F.log("project.clearCustomer", "clear customer");
                    proj.customer.clear();
                    proj.tempCustomer.clear();
                    proj.showCustomerDetail();
                }else{
                    $F.fireValue(instance, "temp.customer_guid", "");
                }
            }
        },
		
		saveCustomer : function() {
			var proj = this;
			return new Promise(function(resolve, reject){
				proj.customer.save(function(customerGuid) {
					if (proj.customer.getProperty("customer_guid") != customerGuid) {
						proj.setCurrentCustomerByGuid(customerGuid);
					}
					resolve();
				}, function(){
					reject();
				}, null, true);
			});
		},

		/**
		 * 根据staffId获取Staff对象
		 * @method getStaffById
		 * @param staffId {string} 账号StaffID
		 * @param callback {function} 回调方法
		 * @return {object} staff对象
		 */
		getStaffById : function(staffId, callback) {
			var proj = this, 
				staff,
				staffs = proj.getCache($CONST.CacheName.STAFF), 
				agents = proj.getCache($CONST.CacheName.AGENT);
            if(! staffs){
            	staffs = {}, agents = {};
        		proj.putCache($CONST.CacheName.STAFF, staffs);
        		proj.putCache($CONST.CacheName.AGENT, agents);
            }
            staff = staffs[staffId];
            if (staff && staff.bean) {
            	if (callback)
            		callback(staff);
            	return staff;
            }

			$F.dataService('SystemDo2', {
				data: $F.sqlbean('System.Staff.getById', proj.token, [$E.staff.epidSql, staffId]),
                digest : proj.digest,
				async: (callback ? true : false),
				success: function(data) {
					if (data.code > 0) {
						if (data.value[0].count > 0) {
							var staffBean = $F.makeJsonBean(data.value[0]);
							staff = {
								id: staffBean.STAFF_ID,
								name: staffBean.STAFFNAME,
								agentId: staffBean.AGENT_ID,
								supervisor: staffBean.ISSUPERVISOR,
								rolegroup: staffBean.DEFAULTROLEGROUP,
								headImg: staffBean.HEADIMG,
								bean : staffBean
							}
							//console.log(staff);
							staffs[staff.id] = staff;
							agents[staff.agentId] = staff;
							if ($.isFunction(callback))
								callback(staff);
						}
					} else
						return $F.err('Project - getStaffById', data.message), null;
				}
			});
			return staff;
		},

		/**
		 * 根据staffId获取Staff对象
		 * @method getStaffByAgentId
		 * @param {string} agentId 账号AgentID
		 * @return {object} staff对象
		 */
		getStaffByAgentId : function(agentId) {
			var proj = this, 
				staff,
				staffs = proj.getCache($CONST.CacheName.STAFF), 
				agents = proj.getCache($CONST.CacheName.AGENT);
            if(! staffs){
            	staffs = {}, agents = {};
        		proj.putCache($CONST.CacheName.STAFF, staffs);
        		proj.putCache($CONST.CacheName.AGENT, agents);
            }
            staff = agents[agentId];
            if (staff)
            	return staff;

			$F.dataService('SystemDo2', {
				data: $F.sqlbean('System.Staff.getByAgentId', proj.token, [$E.staff.epidSql, agentId]),
                digest : proj.digest,
				async: false,
				success: function(data) {
					if (data.code > 0) {
						if (data.value[0].count > 0) {
							var d = data.value[0].fields[0];
							staff = {
								id: d[1],
								name: d[2],
								agentId: d[0],
								supervisor: d[3],
								rolegroup: d[4],
								headImg: d[5]
							}
							//console.log(staff);
							agents[staff.agentId] = staff;
							staffs[staff.id] = staff;
						}
					} else
						return $F.err('Project - getStaffByAgentId', data.message), null;
				}
			});
			return staff;
		},

		/**
		 * 根据staffId获取Staff名称
		 * @method getStaffNameById
		 * @param {string} staffId 账号ID
		 * @return {string} staff名称
		 */
        getStaffNameById : function(staffId){
            var staff = this.getStaffById(staffId);
            if($F.isNull(staff))
                return '';
            return staff.name;
        },

		/**
		 * 根据rolegroupId获取Rolegroup下的所有账号
		 * @method getStaffsByGroupId
		 * @param {string} rolegroupId 组ID
		 * @return {map} staff表
		 */
        getStaffsByGroupId : function(rolegroupId) {
        	var proj = this;
        	var entry = proj.getCache($CONST.CacheName.ROLEGROUPSTAFFS);
        	if (! entry) {
        		entry = {};
        		proj.putCache($CONST.CacheName.ROLEGROUPSTAFFS, entry);
        	}
        	var staffs = entry[rolegroupId];
        	if (staffs)
        		return staffs;

			staffs = {};
			$F.dataService('SystemDo2', {
				data: $F.sqlbean('System.RoleGroup.Staff', proj.token, [rolegroupId]),
                digest : proj.digest,
				async: false,
				success: function(data) {
					if (data.code > 0) {
						if (data.value[0].count > 0) {
							//console.log(data.value[0].fields)
							$.each(data.value[0].fields, function(){
								staffs[this[0]] = this[1];
							})
							entry[rolegroupId] = staffs;
						}
					} else
						$F.err('Project - getStaffsByGroupId', data.message);
				}
			})
			return staffs;
        },

		/**
		 * 获取Rolegroup表
		 * @method getRolegroups
		 * @return {map} rolegroup表
		 */
		getRolegroups : function(callback) {
			var proj = this, entry = proj.getCache($CONST.CacheName.ROLEGROUPS);
			if (! entry) {
				entry = {};
				$F.dataService('SystemDo2', {
					data: $F.sqlbean('System.RoleGroup', proj.token, [$E.staff.epidSql]),
	                digest : proj.digest,
					async: $.isFunction(callback),
					success: function(data) {
						if (data.code > 0) {
							if (data.value[0].count > 0) {
								$.each(data.value[0].fields, function(i, v){
									entry[v[0]] = v[1];
								})
								proj.putCache($CONST.CacheName.ROLEGROUPS, entry);
								if ($.isFunction(callback))
									callback(entry);
							}
						} else
							$F.err('Project - getRolegroups', data.message);
					}
				});
			} else {
				if ($.isFunction(callback))
					callback(entry);
			}
			return entry;
		},

        getRolegroupById : function(rolegroupId) {
            var rolegroups = this.getRolegroups(), entry = rolegroups[rolegroupId];
            if (entry === undefined)
            	return null;
            return {
            	id: rolegroupId,
            	desc: entry
            };
        },

        getRolegroupDescById : function(rolegroupId){
            var rolegroups = this.getRolegroups(), entry = rolegroups[rolegroupId];
            if (entry === undefined)
            	return '';
            return entry.trim();
        },

        getDbType : function(dbpool){
            var dbType = "";
            var mRs= $F.ajaxSync("DBInfo",{
                token : this.token,
                dbPool : dbpool || ""
            }, this.digest);
            if (mRs){
                if (mRs.code>-1){
                    dbType = mRs.value;
                }
            }
            return dbType;
        },

        commonQuerySync : function(sqlKey, params){
            var proj = this;
            var result;
            $F.dataService('SystemDo2', {
                async : false,
                data : $F.sqlbean(sqlKey, proj.token, params),
                digest : proj.digest,
                success: function(data){
                    if (data.code < 1)
                        $F.alert(data.message);
                    if (data.value[0].count >= 0) {
                        result = data;
                    }
                },
                fail : function(xhr){
                    $F.alert("ajax error: "+xhr.responseText);
                }
            });
            return result;
        },

        commonUpdateSync : function(sqlKey, params){
            var proj = this;
            var result = 0;
            $F.dataService('SystemDo1', {
                async : false,
                data: $F.sqlbean(sqlKey, proj.token, params),
                digest : proj.digest,
                success: function(data){
                    if (data.code < 1)
                        return $F.alert(data.message);
                    result = 1;
                },
                fail : function(xhr){
                    result = -1;
                }
            });
            return result;
        },
        
        /**
		 * 根据sqlkey和sql参数，直接返回出查询的字符串,此方法类似jdbctemplate的queryforString,用来直接返回SQL查询单个字段的值
		 * @param sqlKey
		 * @param params
         * @returns string
         */
		queryForString : function(sqlKey, params){
			var str;
			var ret = this.commonQuerySync(sqlKey, params);
			if(ret && ret.value[0].count > 0){
				str = ret.value[0].fields[0][0];
			}
			return str;
		},
		
		/**
		 * 根据sqlkey和sql参数，以传入的主键字段值为key，对应一条记录为value，返回这样的而一个map对象
		 * @param sqlKey
		 * @param params
		 * @param primaryKey
         * @returns {{}}
         */
		queryForMap : function(sqlKey, params, primaryKey){
			var obj;
			var ret = this.commonQuerySync(sqlKey, params);
			if(ret && ret.value[0].count > 0){
				obj = $F.makeJsonArrayMap(ret.value[0], primaryKey);
			}
			return obj;
		},

        /**
         * 对当前操作的数据进行加锁操作
         * @method doLock
         * @param {string} mainId
         * @param {string} subId
         * @return {boolean} 加锁是否成功
         */
        doLock : function(mainId, subId) {
            var proj = this, lock = false;
            $F.dataService('JSGenerateServlet2', {
                data : {
                    token : proj.token,
                    dbPool : '',
                    name : 'System.Locked',
                    mainId : mainId || '',
                    subId : subId || ''
                },
                digest : proj.digest,
                async : false,
                success : function(data) {
                    // console.log(data);
                    if (data.code > 0) {
                        lock = true;
                        $F.notify('系统当前数据已经成功加锁!');
                    } else {
                        if (data.code == -2) {
                            var staff = proj.getStaffById(data.message);
                            $F.alert('当前系统数据已被[ ' + (staff?staff.name:data.message) + ' ]加锁！');
                        } else
                            $F.alert(data.message);
                    }
                }
            });
            return lock;
        },

        /**
         * 对当前操作的数据进行解锁操作
         * @method doUnlock
         * @param {string} mainId
         * @param {string} subId
         * @return {boolean} 解锁是否成功
         */
        doUnlock : function(mainId, subId) {
            var proj = this, unlock = false;
            $F.dataService('JSGenerateServlet2', {
                data : {
                    token : proj.token,
                    dbPool : '',
                    name : 'System.unLocked',
                    mainId : mainId || '',
                    subId : subId || ''
                },
                digest : proj.digest,
                async : false,
                success : function(data) {
                    if (data.code >= 0) {
                        unlock = true;
                    } else
                        $F.warn("解锁失败");
                }
            });
            return unlock;
        },

        /**
         * 对当前操作的数据进行加锁状态检查
         * @method doLockCheck
         * @param {string} mainId
         * @param {string} subId
         * @return {integer} 0:未加锁，1:自己加锁，-2:被别人加锁，-1：未知失败
         */
        doLockCheck : function(mainId, subId) {
            var proj = this, check = -1;
            $F.dataService('JSGenerateServlet2', {
                data : {
                    token : proj.token,
                    dbPool : '',
                    name : 'System.CheckLocked',
                    mainId : mainId || '',
                    subId : subId || ''
                },
                digest : proj.digest,
                async : false,
                success : function(data) {
                    console.log(data);
                    check = data.code;
                }
            });
            return check;
        },

        //虽然mobile中，没有tab概念，但是还是实现了这个方法，用来适配其他文件中调用此方法的地方
        tabClose : function(){
        	if ($E.goback) {
        		$E.goback.click();
        	} else {
        		// 当单独打某个页面时候，比如工单，然后工单关闭时候，就没有地方去goback了
        		location.href = 'success.html'; // 比如说跳转到一个成功提示页面
        	}
        },
    	
    	/**
    	 * 对一个codetable表进行query查询
    	 * @method queryCodetable
    	 * @param tableName {string} 全局SQL名
    	 * @param expression {string} JSONSQL查询条件
    	 * @return {array}
    	 */
    	queryCodetable : function(tableName, expression) {
    		var a = this;
    		a.cache[tableName] || a.loadCodetable(tableName);
    		// console.log('JSONSQL Expression: ' + expression, a.cache[tableName]);
    		if (expression) {
    			expression = expression.replace(/\* where /gi, '* where ');
    			return jsonSql(a.cache[tableName], expression, {trace:false});
    		} else
    			return a.cache[tableName];
    	},
    	
    	/**
    	 * 快速检索返回codetable表的某条记录
    	 * @method getCodetableByKey
    	 * @param tableName {string} 全局SQL名
    	 * @param key {string} 主键值
    	 * @return {object}
    	 */
    	getCodetableByKey : function(tableName, key) {
    		var a = this;
    		a.cache[tableName] || a.loadCodetable(tableName);
    		return a.cache[tableName][key];
    	},
    	
    	loadCodetable : function(tableName) {
			var a = this,
				m = new Date(),
				dataRequest = {
					token: a.token,
					dbPool: '',
					sqls: []
				},
				tnArr = [];
			
			if ($.type(tableName) == 'string') {
				if (a.cache[tableName])
					return;
				dataRequest.sqls.push({
						pubKey: tableName,
						page: 0,
						maxRow: a.pubSqlMaxRows
					})
			} else {
				if (tableName instanceof Array) {
					tableName.forEach(function(item) {
						if (a.cache[item])
							return;
						dataRequest.sqls.push({
							pubKey: item,
							page: 0,
							maxRow: a.pubSqlMaxRows
						})
						tnArr.push(item);
					})
					if (tnArr.length == 0)
						return;
				} else
					return;
			}
			var result = $F.ajaxSync("CacheDoPubSql2", dataRequest, a.digest);
			//console.log(result);
			
			if (result.code > 0) {
				result.value.forEach(function(r, ti) {
					var cName = ($.type(tableName) == 'string' ? tableName : tnArr[ti]);
					if (r.count >= 0) {
						// console.info(result.value[0])
						if ($.type(r.fields) == 'array') {
							a.cache[cName] = {};
							$.each($F.makeJsonArray(r), function(i, v) {
								a.cache[cName]['KEY-' + i] = v;
							})
							console.info('获得' + r.fields.length + '条记录在' + cName + '中');
						} else {
							a.cache[cName] = r.fields;
							var i = 0;
							for(var o in a.cache[cName])
								i ++;
							var str = '获得' + i + '条记录在' + cName + '中';
							if (i < r.count) {
								str += ', 其中可能因为主键重复造成'+ (r.count - i) + '条记录丢失';
								$F.err('Project - loadCodetable', str);
							} else
								console.info(str);
						}
						$F.log(a.id, 'CodeTable - ' + cName + ', took time: ' + (new Date() - m) + '\'ms')
					}else{
						// console.log(result);
						$F.err('Project - loadCodetable', "全局SQL执行失败: " + cName);
					}
				})
			}else{
				throw new Error("全局SQL执行失败: " + result.message);
			}
    	},
    	
    	currentStaff : function() {
    		var a = this;
    		if (! a.currentStaffObject) {
    			$F.dataService('SystemDo2', {
    				data: $F.sqlbean('System.currentStaff', a.token, [$E.staff.epidSql, $E.staff.id]),
                    digest : a.digest,
    				async: false,
    				success: function(data) {
    					if (data.code > 0) {
    						if (data.value[0].count > 0)
    							a.currentStaffObject = $F.makeJsonBean(data.value[0]);
    						else
    							$F.alert($E.staff.id + ' 不存在');
    					}else
    						$F.alert(data.message);
    				}
    			})
    		}
    		return a.currentStaffObject;
    	},
       	
    	currentRolegroup : function() {
    		var a = this;
    		if (! a.currentRolegroupObject) {
    			$F.dataService('SystemDo2', {
    				data: $F.sqlbean('System.currentRolegroup', a.token, [$E.staff.epidSql, a.groupId]),
                    digest : a.digest,
    				async: false,
    				success: function(data) {
    					if (data.code > 0) {
    						if (data.value[0].count > 0)
        						a.currentRolegroupObject = $F.makeJsonBean(data.value[0]);
    						else
    							$F.alert(a.groupId + ' 不存在');
    					}else
    						$F.alert(data.message);
    				}
    			})
    		}
    		return a.currentRolegroupObject;
    	},
    	
    	shieldString : function(string) {
    		if (! string)
    			return '';
    		
    		var TELWLD = this.getParam('TELWLD'),
    			TELSHD = this.getParam('TELSHD'),
    			TELWLF = this.getParam('TELWLF'),
    			TELSHR = this.getParam('TELSHR');
    		return $F.shieldNumber(string, TELWLD, TELSHD, TELWLF, TELSHR);
    	}
	};
	
	var iScrollClick = function(){
		console.info(navigator.userAgent)
		if (/iPhone|iPad|iPod|Macintosh/i.test(navigator.userAgent)) return false;
		if (/Chrome/i.test(navigator.userAgent)) return (/Android/i.test(navigator.userAgent));
		if (/Silk/i.test(navigator.userAgent)) return false;
		if (/Android/i.test(navigator.userAgent)) {
		   var s=navigator.userAgent.substr(navigator.userAgent.indexOf('Android')+8,3);
		   return parseFloat(s[0]+s[3]) < 44 ? false : true
	    }
		return false;
	};
	
	return {
		create : function(id, name, token, digest, groupId, groupName, roles) {
			return new Project(id, name, token, digest, groupId, groupName, roles);
		}
	};
});
